home *** CD-ROM | disk | FTP | other *** search
- /* rs232.h v1.5 */
-
- /* port characteristic definitions for use with rs_initport */
- /* port id's */
- #define RS_PORT1 '1' /* port 1 */
- #define RS_PORT2 '2' /* . */
- #define RS_PORT3 '3' /* . */
- #define RS_PORT4 '4' /* port 4 */
- /* baud rates */
- #define RS_B110 110L /* 110 baud */
- #define RS_B300 300L /* . */
- #define RS_B600 600L /* . */
- #define RS_B1200 1200L /* . */
- #define RS_B2400 2400L /* . */
- #define RS_B4800 4800L /* . */
- #define RS_B9600 9600L /* . */
- #define RS_B19K 19200L /* . */
- #define RS_B38K 38400L /* . */
- #define RS_B57K 57600L /* . */
- #define RS_B115K 115200L /* 115200 baud */
- /* parity */
- #define RS_NOPAR 'N' /* no parity */
- #define RS_EVPAR 'E' /* even parity */
- #define RS_ODPAR 'O' /* odd parity */
- #define RS_SPPAR 'S' /* space parity */
- #define RS_MKPAR 'M' /* mark parity */
- /* data bits */
- #define RS_DBIT8 '8' /* 8 data bits */
- #define RS_DBIT7 '7' /* 7 data bits */
- /* stop bits */
- #define RS_SBIT1 '1' /* 1 stop bit */
- #define RS_SBIT2 '2' /* 2 stop bits */
- /* values returned by rs_initport */
- #define RS_UART4 4 /* init. OK, UART is 16550AF,C,CF */
- #define RS_UART3 3 /* init. OK, UART is 16550 */
- #define RS_UART2 2 /* init. OK, UART is 8250A or 16450 */
- #define RS_UART1 1 /* init. OK, UART is 8250 or 8250B */
- #define RS_NOUART 0 /* init. failed - no UART detected */
- #define RS_BADIBUF -1 /* init. failed - in. buffer or size bad */
- #define RS_BADOBUF -2 /* init. failed - out. buffer or size bad */
- #define RS_BADPORT -3 /* init. failed - invalid port argument */
- #define RS_BADPAR -4 /* init. failed - invalid parity argument */
- #define RS_BADDBIT -5 /* init. failed - invalid data bits argument */
- #define RS_BADSBIT -6 /* init. failed - invalid stop bits argument */
- #define RS_BADBAUD -7 /* init. failed - invalid baud argument */
-
- /* bit definitions to test value returned by rs_error */
- #define RS_RBER 0x01 /* Receive data overrun (receive buffer) */
- #define RS_ROER 0x02 /* Receive data overrun (UART) */
- #define RS_PERR 0x04 /* Parity error */
- #define RS_FERR 0x08 /* Framing error */
- #define RS_BKDT 0x10 /* Break detected */
- #define RS_FFER 0x80 /* Error in receive FIFO */
-
- /* definitions for use with rs_modctrl */
- #define RS_GETMSR 0 /* command to read state of modem status lines */
- /* bit definitions to test value returned with RS_GETMSR cmd */
- #define RS_CTSCHG 0x01 /* CTS changed states */
- #define RS_DSRCHG 0x02 /* DSR changed states */
- #define RS_RICHG 0x04 /* RI changed states */
- #define RS_DCDCHG 0x08 /* DCD changed states */
- #define RS_CTSSTE 0x10 /* state of CTS */
- #define RS_DSRSTE 0x20 /* state of DSR */
- #define RS_RISTE 0x40 /* state of RI */
- #define RS_DCDSTE 0x80 /* state of DCD */
- #define RS_WRTMCR 1 /* command to control hardware control lines */
- /* parameter1 definitions for use with RS_WRTMCR and RS_GETMCR commands */
- #define RS_MCRDTR 1 /* DTR line */
- #define RS_MCRRTS 2 /* RTS line */
- /* parameter2 definitions for use with RS_WRTMCR command */
- #define RS_LINON 1 /* turn selected line on */
- #define RS_LINOFF 0 /* turn selected line off */
- #define RS_GETMCR 2 /* command to return current state of modem control reg. */
-
- /* command definitions for rs_timer */
- #define RS_CLRTIM 0 /* return timer count, set timer to 0 */
- #define RS_GETTIM 1 /* return timer count, do not clear */
-
- /* definitions for rs_setflow */
- #define RS_FLWOFF 0 /* command to turn flow control off */
- #define RS_FLWHDW 1 /* command to turn hardware flow control on */
- /* parameter1 bit definitions for use with RS_FLWHDW command */
- #define RS_FLWCTS 1 /* use CTS line */
- #define RS_FLWDSR 2 /* use DSR line */
- #define RS_FLWRI 4 /* use RI line */
- #define RS_FLWDCD 8 /* use DCD line */
- #define RS_FLWXON 2 /* command to turn XON/XOFF flow control on */
- /* parameter1 and parameter2 definitions for use with RS_FLWXON */
- #define RS_XON 0x11 /* standard XON character */
- #define RS_XOFF 0x13 /* standard XOFF character */
- #define RS_FLWSTAT 3 /* command to return status of flow control */
- /* values returned by RS_FLWSTAT command */
- #define RS_FLWHLT 1 /* output halted by flow control */
- #define RS_FLWNHLT 0 /* output not halted by flow control */
- #define RS_FLWINS 4 /* command to insert control byte in output stream */
-
- /*****************************************************************/
- /*** function prototypes ***/
- /*****************************************************************/
- /* interrupt handler */
- void interrupt rs_inthndlr(void);
-
- /* port initialization: Sets up port parameters, installs interrupt
- vector, enables interrupts. Input and output buffers are 'rotary'
- buffers - buffer size must be a power of 2. Function returns the
- following:
- 4 - Success, 16550 UART, FIFOs enabled.
- 3 - Success, 16550 UART, FIFOs unavailable.
- 2 - Success, 8250A or 16450 UART
- 1 - Success, 8250B UART
- 0 - Fail, no UART detected
- -1 - Fail, bad input buffer
- -2 - Fail, bad output buffer
- -3 - Fail, bad port argument
- -4 - Fail, bad parity argument
- -5 - Fail, bad data bits argument
- -6 - Fail, bad stop bits argument
- -7 - Fail, bad baud argument
- Example:
- status = rs_initport(port,baud,parity,bits,stop,in_bufsize,in_bufptr,\
- out_bufsize,out_bufptr);
- port = '1','2','3', or '4'
- baud = 110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600 or 115200
- parity = 'N', 'E', 'O', 'S' or 'M'
- bits = '7' or '8'
- stop = '1' or '2'
- in_bufsize = (power of 2) >= 2 <= 32768
- in_bufptr = char pointer to previously allocated input buffer
- out_bufsize = (power of 2) >= 2 <= 32768
- out_bufptr = char pointer to previously allocated output buffer */
- int rs_initport(char, long, char, char, char,
- unsigned, char *, unsigned, char *);
-
- /* Send single byte out port - if no room in output buffer, wait
- til there's room. Return 0 on success, or -1 if no room in
- output buffer and output is currently disabled via flow control
- or if port is unavailable. If RS_POLLED_XMIT is defined, xmit buffer
- and xmit interrupts are not used. */
- int rs_sndbyt(int);
-
- /* Send string of specified length out port - if no room in output
- buffer, waits til there's room. Return 0 on success or number of
- bytes copied to output buffer if not enough room for entire string
- and output is currently disabled via flow control. Returns -1 if
- port is not available. If length is 0 (unspecified), send chars
- from string up to but not including terminating nul character.
- If RS_POLLED_XMIT is defined in header, xmit interrupts are not used
- and the function does not return until the string has been sent. */
- int rs_sndstr(int,char *);
-
- /* Get single char, return -1 if none available or port is not
- available. */
- int rs_getbyt(void);
-
- /* Get specified number of characters from input buffer. If less
- than the specified number of characters are available, get as
- many as are available. If length of string is unspecified (0),
- copy characters up to and including terminating nul. Return number
- of characters copied or -1 if port is unavailable. Null terminate
- string. */
- int rs_getstr(int, char *);
-
- /* Return number of characters waiting to be read from input buffer. */
- unsigned rs_inrcvd(void);
-
- /* Return amount of free space in output buffer. */
- unsigned rs_outfre(void);
-
- /* Return code for last error detected as follows:
- bit 0: 1 = Receive overrun (buffer)
- bit 1: 1 = Receive overrun (UART)
- bit 2: 1 = Parity error
- bit 3: 1 = Framing error
- bit 4: 1 = Break detected
- bit 7: 1 = Error in receive FIFO
- Return 0 if no error since last call to rs_error() */
- int rs_error(void);
-
- /* If rs_cmd = 0, return modem status as follows:
- bit 0: CTS line changed state
- bit 1: DTR line change state
- bit 2: RI line changed state
- bit 3: DCD line changed state
- bit 4: current state of CTS line
- bit 5: current state of DTR line
- bit 6: current state of RI line
- bit 7: current state of DCD line
- Bits 0 - 3 will be 0 unless a status line has changed states since
- the last call to rs_modctrl();
- If rs_cmd = 1, parameter 1 is bit pattern for line to control.
- Parameter2 = 0 turns line off, parameter 2 = 1 turns line on.
- Returns -1 if port is unavailable. */
- int rs_modctrl(int rs_cmd,...);
-
- /* Send break to remote. Return -1 if port is unavailable. */
- int rs_break(void);
-
- /* clear output buffer of any bytes not yet sent */
- void rs_clrout(void);
-
- /* clear input buffer of any bytes received but not yet read */
- void rs_clrin(void);
-
- /* return 0 if no keystrokes pending, 1 if key has been pressed */
- int rs_keyhit(void);
-
- /* If rs_cmd = 0, set timer to 0 and return 18.2Hz tick count since
- timer was last zeroed or port was initialized.
- If rs_cmd = 1, return current value of timer.*/
- unsigned rs_timer(int rs_cmd);
-
- /* Set flow control characteristics or check status
- rs_cmd = 0: Turn flow control off
- rs_cmd = 1: Set flow control to hardware. Parameter1
- is hardware line to monitor.
- rs_cmd = 2: Set flow control to XON/XOFF - Parameter1
- is character to use for XON, Parameter2
- is character to use for XOFF.
- rs_cmd = 3: Return status of flow control - 0 = output
- normal, 1 = output halted
- rs_cmd = 4: Insert control character in output stream.
- Parameter1 is control character.
- Returns -1 if port is unavailable */
- int rs_setflow(int rs_cmd,...);
-
- /* Call this function before exiting program or when finished with port.
- Restores interrupt vector and interrupt mask, and disables port
- interrupts. */
- void rs_close(void);
-
- /********************* Cut here for seperate header file *********************/
- /***
-
- RS232: Set of general purpose functions providing fully buffered
- interrupt driven serial I/0. Supports baud rates from 110 to
- 115.2K on serial ports 1 - 4. Compiled and tested with Turbo C 2.0,
- Turbo C++, Borland C++ 2.0, Borland C++ 3.1.
-
- 3/5/92
- v1.5
- revised 10/12/92, 11/2/92, 12/13/92, 2/7/93, 5/2/93
- copyrght. C. Karcher 1992,93
- Seattle WA
- CSID 76406,536
-
- 11/2/92 Fixed rs_sndstr bug: sending string longer than buffer len.
- Fixed rs_timer bug: when timer was cleared and then read
- before it had a chance to increment past 0, 176 was returned.
- Fixed bug in interrupt service routine which prevented rs_sndstr
- from working with modem board which emulates 8250B UART.
-
- 12/13/92 Corrected unterminated comment in rs_initport where defining
- rs_ss.fcr. Changed timer rollover constant type from L to UL
- in rs_timer.
-
- 1/9/93 Fixed bug in rs_initport where defining base address for ports
- 3 and 4 - IRQ number and interrupt mask was left unitialized
- if BIOS data area showed no base address for port.
-
- 2/7/93 Corrected bug in interrupt service routine which caused
- receive FIFO to be read incorrectly. Corrected bug in
- rs_sndsr and rs_sndbyt preventing an xmit interrupt from
- being generated. Added preprocessor directives and code
- to use polling method instead of interrupts for character
- transmission if RS_POLLED_XMIT is defined.
-
- 5/2/93 Added preprocessor directives in interrupt service routine
- to prevent code generated by TC2.0 and earlier from trashing
- incoming characters in large memory models.
-
- ***/
-
- #include<dos.h> /* need dos.h for port i/o and interrupt funcs. */
- #include<stdarg.h> /* for variable arguments in some functions */
-
- #ifndef NULL
- #if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
- #define NULL 0
- #else
- #define NULL 0L
- #endif
- #endif
-
- unsigned rs_timer(int rs_cmd);
- void rs_close(void);
-
- /*****************************************************************/
- /*** global variables - all names begin with rs_ ***/
- /*****************************************************************/
- struct rs_statics{ /* static variables */
- int int_no;
- int flow;
- int xmitfifo;
- int thr;
- int rbr;
- int iir;
- int fcr;
- int ier;
- int mcr;
- int lsr;
- int lcr;
- int msr;
- int uart;
- unsigned ibuf_siz;
- unsigned obuf_siz;
- char xon;
- char xoff;
- char hdw_flw;
- unsigned char *in_buf;
- unsigned char *out_buf;
- unsigned char oldmask;
- }rs_ss;
-
- volatile struct rs_dynamics{ /* dynamic variables */
- unsigned in_head;
- unsigned in_tail;
- unsigned out_head;
- unsigned out_tail;
- unsigned rcv_cnt;
- unsigned char ier_msk;
- unsigned char msr_cod;
- unsigned char err_cod;
- }rs_ds;
-
- int rs_portopen = 0;
- void interrupt (*rs_oldvec)(void) = NULL;
-
- /* Interrupt service routine - Get received character from port rs_ss.rbr,
- store in rs_ss.in_buf and increment rs_inrcv. If flow control enabled,
- update global variable rs_ss.iermsk to enable or disable output as
- required */
- void interrupt rs_inthndlr(void)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
- extern void interrupt (*rs_oldvec)(void);
- int rs_xmitcnt;
-
- #ifndef RS_POLLED_XMIT
- if(rs_ss.uart)
- outportb(rs_ss.ier,rs_ds.ier_msk); /* nudge interrupt if not 8250B */
- #endif
- _AL = (inportb(rs_ss.iir) & '\x07'); /* get interrupt id */
- if(!(_AL & '\x01')){ /* interrupt pending ? */
- do{
- if(_AL == '\x06'){ /* receive error ? */
- rs_ds.err_cod = inportb(rs_ss.lsr); /* record error */
- }
- else if((_AL & '\x04')){ /* data received interrupt ? */
- do{
- _AL = inportb(rs_ss.rbr); /* get the byte */
- #if defined(__TURBOC__) && (__TURBOC__ <= 0x0200)
- #if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__)
- _CL = _AL;
- #endif
- #endif
- if(rs_ss.flow == 2){
- if(_AL == rs_ss.xon){
- #ifndef RS_POLLED_XMIT
- outportb(rs_ss.ier,'\x0F');
- #endif
- rs_ds.ier_msk = '\x0F';
- }
- else if(_AL == rs_ss.xoff){
- #ifndef RS_POLLED_XMIT
- outportb(rs_ss.ier,'\x0D');
- #endif
- rs_ds.ier_msk = '\x0D';
- }
- else
- goto rs_J1;
- }
- else{
- /* store incoming byte */
- rs_J1:
- #if defined(__TURBOC__) && (__TURBOC__ <= 0x0200)
- #if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__)
- *(rs_ss.in_buf + rs_ds.in_head++) = _CL;
- #else
- *(rs_ss.in_buf + rs_ds.in_head++) = _AL;
- #endif
- #else
- *(rs_ss.in_buf + rs_ds.in_head++) = _AL;
- #endif
- /* in case head ptr wrapped around */
- rs_ds.in_head &= rs_ss.ibuf_siz;
- rs_ds.rcv_cnt++; /* track rcv buffer overflow */
- }
- }while(inportb(rs_ss.lsr) & '\x01'); /* loop while data avail. */
- }
- #ifndef RS_POLLED_XMIT
- else if(_AL & '\x02'){ /* transmit holding reg. empty ? */
- for(rs_xmitcnt = 0;rs_xmitcnt < rs_ss.xmitfifo;rs_xmitcnt++){
- /* send a byte if any to send */
- if(rs_ds.out_tail != rs_ds.out_head){
- outportb(rs_ss.thr,*(rs_ss.out_buf + rs_ds.out_tail++));
- /* in case tail pointer wrapped around */
- rs_ds.out_tail &= rs_ss.obuf_siz;
- }
- else
- break;
- }
- }
- #endif
- else{ /* change in one of the modem control lines */
- rs_ds.msr_cod = inportb(rs_ss.msr); /* record modem status */
- if(rs_ss.flow == 1){
- if(rs_ds.msr_cod & rs_ss.hdw_flw)
- rs_ds.ier_msk = '\x0F'; /* enable xmit interrupts */
- else
- rs_ds.ier_msk = '\x0D'; /* disable xmit interrupts */
- outportb(rs_ss.ier,rs_ds.ier_msk);
- }
- }
- }while(!((_AL = inportb(rs_ss.iir)) & '\x01')); /* loop if int. pending */
- }
- else
- rs_oldvec(); /* no interrupt pending on entry - call old isr */
-
-
- enable(); /* enable interrupts */
- outportb('\x20','\x20'); /* non-specific EOI to 8259 */
-
- }
-
- /* rs_initport: Initialize port, interrupt vector and interrupt mask (see
- description with function prototype for details on arguments). */
- int rs_initport(char rs_port,long rs_baud,char rs_parity,char rs_bits,
- char rs_stop,unsigned rs_userinbufsiz, char *rs_userinbuf,
- unsigned rs_useroutbufsiz,char *rs_useroutbuf)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
- extern int rs_portopen;
- extern void interrupt (*rs_oldvec)(void);
- void interrupt (*rs_intfnc)(void);
- int rs_init[] = {0x6328,0x2029,0x2E43,0x4B20,0x7261,0x6863,0x7265,
- 0x3120,0x3939,0x2033};
- int rs_dll,rs_dlm,rs_portbase,rs_ret;
- int far *rs_bda;
- unsigned char rs_dvsrl,rs_dvsrh,rs_mask,rs_irq,rs_tmp1,rs_tmp2,rs_tmp3;
-
-
- if(rs_portopen) /* if there's already a port open, close it */
- rs_close();
- rs_ss.oldmask = '\0';
-
- /* make sure buffer size is valid */
- if((rs_userinbufsiz - 1) & rs_userinbufsiz)
- return -1;
- rs_ss.ibuf_siz = rs_userinbufsiz - 1;
- if((rs_ss.in_buf = (unsigned char *)rs_userinbuf) == NULL)
- return -1;
- #ifndef RS_POLLED_XMIT
- if((rs_useroutbufsiz - 1) & rs_useroutbufsiz)
- return -2;
- rs_ss.obuf_siz = rs_useroutbufsiz - 1;
- if((rs_ss.out_buf = (unsigned char *)rs_useroutbuf) == NULL)
- return -2;
- #endif
-
- /* initialize buffer head and tail pointers */
- rs_ds.in_head = rs_ds.in_tail = rs_ds.out_head = rs_ds.out_tail = 0;
-
- if(rs_init[1])
- rs_bda = (int far*)MK_FP(0x40,0); /* get far pointer to BIOS data area */
-
- switch(rs_port){ /* find i/o port address, interrupt number & mask */
- case '1':
- rs_portbase = *rs_bda;
- if(rs_portbase == 0)
- rs_portbase = 0x3F8;
- rs_ss.int_no = 0x0C;
- rs_mask = '\xEF';
- rs_irq = 4;
- break;
- case '2':
- rs_portbase = *(rs_bda + 1);
- if(rs_portbase == 0)
- rs_portbase = 0x3FE;
- rs_ss.int_no = 0x0B;
- rs_mask = '\xF7';
- rs_irq = 3;
- break;
- case '3':
- rs_portbase = *(rs_bda + 2);
- if(rs_portbase == 0)
- rs_portbase = 0x3E8;
- if(rs_portbase == 0x3220){ /* if it's a PS/2 */
- rs_ss.int_no = 0x0B;
- rs_mask = '\xF7';
- rs_irq = 3;
- }
- else{
- rs_ss.int_no = 0x0C;
- rs_mask = '\xEF';
- rs_irq = 4;
- }
- break;
- case '4':
- rs_portbase = *(rs_bda + 3);
- if(rs_portbase == 0)
- rs_portbase = 0x2E8;
- if(rs_portbase == 0x3228){ /* if it's a PS/2 */
- rs_ss.int_no = 0x0C;
- rs_mask = '\xEF';
- rs_irq = 4;
- }
- else{
- rs_ss.int_no = 0x0B;
- rs_mask = '\xF7';
- rs_irq = 3;
- }
- break;
- default:
- return -3;
- }
-
- switch(rs_parity){
- case 'N':
- rs_parity = 0;
- break;
- case 'E':
- rs_parity = '\x18';
- break;
- case 'O':
- rs_parity = '\x08';
- break;
- case 'S':
- rs_parity = '\x38';
- break;
- case 'M':
- rs_parity = '\x28';
- break;
- default:
- return -4;
- }
-
- if(rs_bits == '7')
- rs_bits = 2;
- else if(rs_bits == '8')
- rs_bits = 3;
- else
- return -5;
-
- if(rs_stop == '1')
- rs_stop = 0;
- else if(rs_stop == '2')
- rs_stop = 4;
- else
- return -6;
-
- /* 8250 (or 16x50) registers: */
- /* out, bit 7 of LCR = 0, (Transmit Holding Register) */
- rs_ss.thr = rs_portbase + 0;
- /* in, bit 7 of LCR = 0, (Receive Buffer Register) */
- rs_ss.rbr = rs_portbase + 0;
- /* out, bit 7 of LCR = 1, (Divisor Latch LSB) */
- rs_dll = rs_portbase + 0;
- /* out, bit 7 of LCR = 1, (Divisor Latch MSB) */
- rs_dlm = rs_portbase + 1;
- /* out, bit 7 of LCR = 0, (Interrupt Enable Register)
- bit 0 = 1 data rcvd
- bit 1 = 1 transmit holding reg. empty
- bit 2 = 1 data reception error
- bit 3 = 1 change in modem status
- bit 4-7 unused */
- rs_ss.ier = rs_portbase + 1;
- /* in, (Interrupt ID register)
- bit 0 : 0 = interrupt pending
- bits 2-1: 00 = modem status change - read status
- 01 = transmit ready - output character or
- read iir to clear
- 10 = data rcvd - read data
- 11 = break or error
- bits 7-6: 11 = 16550 in FIFO mode */
- rs_ss.iir = rs_portbase + 2;
- /* out, (FIFO control register - 16550)
- bit 0: 1 = FIFO enable
- bit 1: 1 = RCVR FIFO reset
- bit 2: 1 = XMIT FIFO reset
- bit 6 & 7: RCVR trigger level
- (00 = 1, 01 = 4, 10 = 8, 11 = 14) */
- rs_ss.fcr = rs_portbase + 2;
- /* out, (Line Control Register)
- bits 0-1: Character Length
- 00 = 5 bits
- 01 = 6 bits
- 10 = 7 bits
- 11 = 8 bits
- bit 2: Number of stop bits
- 0 = 1 (1.5 if character length 5)
- 1 = 2
- bit 3: Parity
- 0 = no parity
- 1 = parity generated
- bit 4: Parity type
- 0 = odd
- 1 = even
- bit 5: Stick Parity
- 0 = disabled
- 1 = always 1 if bit 3 = 1 & bit 4 = 0 or
- always 0 if bit 3 = 1 & bit 4 = 1 or
- no parity if bit 3 = 0
- bit 6: Set Break
- 0 = disabled
- 1 = output string of 0s
- bit 7: Enable write to baud divisor regs. if 1 */
- rs_ss.lcr = rs_portbase + 3;
- /* out, (Modem Control Register)
- bit 0: 1 = data terminal ready
- bit 1: 1 = request to send
- bit 2: 1 = aux. output 1
- bit 3: 1 = aux. output 2 - enables hdwr intrrpts.
- bit 4: 1 = UART loopback mode
- bit 5-7: always 0 */
- rs_ss.mcr = rs_portbase + 4;
- /* in, (Line Status Register)
- bit 0: 1 = character received
- bit 1: 1 = rcvd data overrun
- bit 2: 1 = parity error
- bit 3: 1 = framing error
- bit 4: 1 = break detected
- bit 5: 1 = transmit holding reg. empty
- bit 6: 1 = transmitter empty
- bit 7: 1 = rcvr FIFO error (16550) */
- rs_ss.lsr = rs_portbase + 5;
- /* in, (Modem Status Register)
- bit 0: 1 = delta clear to send
- bit 1: 1 = delta data set ready
- bit 2: 1 = delta ring indicator
- bit 3: 1 = delta data carrier detect
- bit 4: 1 = clear to send
- bit 5: 1 = data set ready
- bit 6: 1 = ring indicator
- bit 7: 1 = data carrier detect */
- rs_ss.msr = rs_portbase + 6;
-
- /* check for existence of UART */
- outportb(rs_ss.fcr,'\0'); /* if 16550, make it a 16450 */
- rs_tmp1 = inportb(rs_ss.mcr); /* save mcr */
- rs_tmp2 = inportb(rs_ss.ier); /* save ier */
- outportb(rs_ss.ier,'\0'); /* disable interrupts at UART */
- inportb(rs_ss.rbr); /* read rcv buffer register */
- inportb(rs_ss.lsr); /* read lsr */
- inportb(rs_ss.msr); /* read msr */
- inportb(rs_ss.iir); /* read iir */
- if(inportb(rs_ss.iir) != '\x01') /* read it again, should indicate... */
- return 0; /* ...no interrupt pending */
- outportb(rs_ss.lcr,'\0'); /* make sure out2 is 0 */
- outportb(rs_ss.ier,'\x02'); /* enable thre interrupt indication */
- goto rs_J1; /* give UART some time */
- rs_J1:
- rs_tmp3 = inportb(rs_ss.iir); /* get iir */
- outportb(rs_ss.ier,rs_tmp2); /* restore original values */
- outportb(rs_ss.mcr,rs_tmp1);
- if(rs_tmp3 != '\x02') /* should have seen thre interrupt... */
- return 0; /* ...else port is unavailable */
-
- /* find out what kind of UART it is */
- rs_ss.xmitfifo = 1; /* initialize for no FIFO */
- outportb(rs_portbase + 7,'\x55'); /* try writing scratch register */
- if(inportb(rs_portbase + 7) != '\x55') /* and then reading it */
- rs_ret = 1; /* if value written wasn't read it's an 8250B */
- else{
- /* check for presence of 16550, if 16550A,C,CF, enable FIFOs */
- outportb(rs_ss.fcr,'\x41'); /* enable FIFO's with 4 byte RCVR trig. level */
- rs_tmp1 = inportb(rs_ss.iir);
- rs_tmp1 &= '\xC0';
- if(rs_tmp1 == (unsigned char)'\xC0'){ /* 16550A,C,CF bits 6 & 7 are set */
- rs_ret = 4;
- rs_ss.xmitfifo = 16; /* #of bytes to write to XMIT FIFO per interrupt */
- }
- else{ /* otherwise, it's an 8250A, 16450 or 16550 */
- outportb(rs_ss.fcr,'\x0');
- if(rs_tmp1 == (unsigned char)'\x80') /* 16550 */
- rs_ret = 3;
- else /* 8250A or 16450 */
- rs_ret = 2;
- }
- }
-
- /* get the baud rate divisor values */
- rs_dvsrh = 0;
- switch(rs_baud){
- case 110L:
- rs_dvsrh = '\x04';
- rs_dvsrl = '\x17';
- break;
- case 300L:
- rs_dvsrh = '\x01';
- rs_dvsrl = '\x80';
- break;
- case 600L:
- rs_dvsrl = '\xC0';
- break;
- case 1200L:
- rs_dvsrl = '\x60';
- break;
- case 2400L:
- rs_dvsrl = '\x30';
- break;
- case 4800L:
- rs_dvsrl = '\x18';
- break;
- case 9600L:
- rs_dvsrl = '\x0C';
- break;
- case 19200L:
- rs_dvsrl = '\x06';
- break;
- case 38400L:
- rs_dvsrl = '\x03';
- break;
- case 57600L:
- rs_dvsrl = '\x02';
- break;
- case 115200L:
- rs_dvsrl = '\x01';
- break;
- default:
- return -7;
- }
-
- rs_oldvec = getvect(rs_ss.int_no); /* get the old interrupt vector */
- setvect(rs_ss.int_no,rs_inthndlr); /* plug in the new one */
-
- outportb(rs_ss.ier,0); /* disable UART interrupts */
- outportb(rs_ss.lcr,'\x80'); /* enable baud rate divisor registers */
- outportb(rs_dll,rs_dvsrl); /* write divisor lo byte */
- outportb(rs_dlm,rs_dvsrh); /* write divisor hi byte */
- outportb(rs_ss.lcr,(rs_parity | rs_bits | rs_stop)); /* characteristics */
- /* enable interrupts at UART, do not change modem control lines */
- outportb(rs_ss.mcr,(inportb(rs_ss.mcr) | '\x08')); /* set out2 */
- inportb(rs_ss.iir); /* clear out any data...*/
- inportb(rs_ss.lsr); /*...left in...*/
- inportb(rs_ss.rbr); /*...UART's status...*/
- inportb(rs_ss.msr); /*...registers */
-
- disable();
- outportb(rs_ss.ier,'\x0D'); /* enable UART interrupts */
- inportb(rs_ss.iir);
- outportb(0x20,('\xC0' | (rs_irq - 1))); /* change 8259 interrupt priorities */
- rs_ss.oldmask = inportb(0x21); /* save old interrupt controller mask */
- rs_mask &= rs_ss.oldmask;
- outportb(0x21,rs_mask); /* interrupt now enabled */
- rs_ds.msr_cod = inportb(rs_ss.msr) & '\xF0'; /* initialize modem status */
- enable();
-
- rs_timer(0); /* zero out tick counter */
- rs_ss.flow = 0; /* initialize flow control */
- rs_ds.rcv_cnt = 0; /* initialize receive count */
- rs_ds.ier_msk = '\x0F'; /* insure that xmit interrupts stay enabled */
- rs_ds.err_cod = '\x00'; /* initialize error flags */
-
- rs_portopen = 1; /* set port open flag */
- rs_ss.uart = rs_ret - 1; /* set UART type */
- return rs_ret;
-
- }
-
- /* rs_close: Restore original 8259 interrupt controller mask value and
- interrupt priorities. Disable UART interrupts and restore original
- interrupt vector. */
- void rs_close(void)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
- extern int rs_portopen;
- extern void interrupt (*rs_oldvec)(void);
- unsigned rs_time,rs_tail;
-
- if(! rs_portopen) /* no port to close */
- return;
-
- /* if buffer xmit in progress, wait til it's done */
- if(rs_ds.ier_msk == '\x0F'){
- rs_time = rs_timer(1);
- rs_tail = rs_ds.out_tail;
- while(rs_ds.out_head != rs_ds.out_tail)
- /* make sure output is moving else time out (wait one char period) */
- if(rs_timer(1) - rs_time > 4 && rs_tail == rs_ds.out_tail)
- break;
- }
-
- /* insure that tranmitter is empty before continuing */
- rs_time = rs_timer(1);
- while(! (inportb(rs_ss.lsr) & '\x40'))
- if(rs_timer(1) - rs_time > 4)
- break;
-
- if(rs_ss.oldmask){
- disable();
- outportb(0x21,rs_ss.oldmask); /* restore old interrupt mask value */
- outportb(0x20,'\xC7'); /* restore interrupt priorities */
- enable();
- }
-
- /* disable UART interrupts */
- outportb(rs_ss.ier,0);
- outportb(rs_ss.mcr,inportb(rs_ss.mcr) & '\xF7');
-
- /* restore old interrupt vector */
- if(rs_oldvec != NULL)
- setvect(rs_ss.int_no,rs_oldvec);
- rs_oldvec = NULL;
-
- rs_portopen = 0; /* signal port closed */
-
- }
-
- /* rs_sndbyt: Output byte via output buffer. If no space in output buffer,
- wait til there is unless output is disabled via flow control, in which
- case return -1. If RS_POLLED_XMIT is defined, the byte is written to
- the port when the transmit holding register becomes empy. THRE interrupt
- and output buffer are not used. Return -1 if output disabled via flow
- control. */
-
- int rs_sndbyt(int rs_snd)
- {
-
- extern int rs_portopen;
- extern volatile struct rs_dynamics rs_ds;
- extern struct rs_statics rs_ss;
-
-
- if(! rs_portopen) /* is a port open ? */
- return -1;
-
- #ifndef RS_POLLED_XMIT /* interrupt driven output */
- while(((rs_ds.out_head + 1) & rs_ss.obuf_siz) == rs_ds.out_tail){
- /* make sure there's room in the buffer */
- /* if xmit disabled via flow control, don't wait */
- if(rs_ds.ier_msk == '\x0D')
- return -1;
- }
- disable();
- *(rs_ss.out_buf + rs_ds.out_head++) = (unsigned char)rs_snd;
- rs_ds.out_head &= rs_ss.obuf_siz;
- enable();
- if(rs_ds.ier_msk != '\x0D'){
- outportb(rs_ss.ier,'\x0D');
- if(! rs_ss.uart) /* if it's an 8250 or 8250B... */
- while(! (inportb(rs_ss.lsr) & '\x20')) /* ...wait for THRE */
- ;
- outportb(rs_ss.ier,'\x0F'); /* generate an interrupt if needed */
- }
- #else /* polled mode output */
- if(rs_ds.ier_msk == '\x0D')
- return -1;
- while(! (inportb(rs_ss.lsr) & '\x20')) /* wait for THRE */
- ;
- outportb(rs_ss.thr,(unsigned char)rs_snd);
- #endif
- return 0;
-
- }
-
-
- /* rs_sndstr: Output rs_sndcnt chars from rs_str to output buffer. If not
- enough space in output buffer, wait til there is. If output disabled
- via flow control, return count of characters written to output buffer
- if less than string length. If rs_sndcnt is 0, output characters from
- rs_str until nul character is reached. If RS_POLLED_XMIT is defined,
- string is written to port by polling the line status register for THRE
- and the buffer is not used. If output is disabled via flow control,
- return count of characters sent */
-
- int rs_sndstr(int rs_sndcnt, char *rs_str)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
- int rs_x,rs_y;
-
- if(! rs_portopen) /* is a port open? */
- return -1;
-
- if(rs_sndcnt) /* string length specified? */
- rs_y = rs_sndcnt;
- else
- rs_y = 0x7FFF; /* max buffer length (`11/2) */
-
- #ifndef RS_POLLED_XMIT /* interrupt driven transmit */
- for(rs_x = 0;rs_x < rs_y;rs_x++){
- /* if no string length specified, stop when nul is encountered */
- if(! rs_sndcnt){
- if(*(rs_str + rs_x) == '\0')
- break;
- }
- while(((rs_ds.out_head + 1) & rs_ss.obuf_siz) == rs_ds.out_tail){
- /* if xmit disabled via flow control,don't wait */
- if(rs_ds.ier_msk == '\x0D')
- return rs_x;
- else{ /* otherwise, may need to get xmit interrupts going (`11/2) */
- outportb(rs_ss.ier,'\x0D');
- if(! rs_ss.uart) /* if it's an 8250 or 8250B... */
- while(! (inportb(rs_ss.lsr) & '\x20')) /* wait for THRE */
- ;
- outportb(rs_ss.ier,'\x0F'); /* kick transmit interrupt */
- }
- }
- disable();
- *(rs_ss.out_buf + rs_ds.out_head++) = (unsigned char)*(rs_str + rs_x);
- rs_ds.out_head &= rs_ss.obuf_siz;
- enable();
- }
- if(rs_ds.ier_msk != '\x0D'){
- outportb(rs_ss.ier,'\x0D');
- if(! rs_ss.uart)
- while(! (inportb(rs_ss.lsr) & '\x20'))
- ;
- outportb(rs_ss.ier,'\x0F'); /* generate an interrupt if needed */
- }
- #else /* polled transmit */
- for(rs_x = 0;rs_x < rs_y;rs_x++){
- /* if xmit disabled via flow control,don't wait */
- if(rs_ds.ier_msk == '\x0D')
- return rs_x;
- /* if no string length specified, stop when nul is encountered */
- if(! rs_sndcnt){
- if(*(rs_str + rs_x) == '\0')
- break;
- }
- while(! (inportb(rs_ss.lsr) & '\x20'))
- ;
- outportb(rs_ss.thr,(unsigned char)*(rs_str + rs_x));
- }
- #endif
- return 0;
-
- }
-
-
- /* rs_outfre: Return amount of free space available in output buffer.
- This function does not return a meaningful value if RS_POLLED_XMIT is
- defined because transmission does not use the buffer */
- unsigned rs_outfre(void)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
-
- return(rs_ss.obuf_siz + 1 - ((rs_ds.out_head - rs_ds.out_tail) &
- rs_ss.obuf_siz));
-
- }
-
- /* rs_getbyt: Return next available character from input buffer - return
- -1 if none are available */
- int rs_getbyt(void)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
- extern int rs_portopen;
- unsigned char rs_byt;
-
- if(! rs_portopen) /* is a port open? */
- return -1;
-
- if(! rs_ds.rcv_cnt) /* char available ? */
- return -1;
- rs_byt = *(rs_ss.in_buf + rs_ds.in_tail++);
- rs_ds.rcv_cnt--;
- rs_ds.in_tail &= rs_ss.ibuf_siz;
- return (int)rs_byt;
-
- }
-
- /* rs_getstr: Get specified number of bytes from port buffer and place in
- user specified buffer. Null terminate string. If receive buffer
- has fewer than the requested number of characters available, copy all
- that are available. Return number of bytes copied. If rs_getcnt is 0,
- copy characters until a nul is encountered (include it in getbuf) */
- int rs_getstr(int rs_getcnt,char *rs_getbuf)
- {
-
- extern struct rs_statics rs_ss;
- extern int rs_portopen;
- int rs_x = 0;
- int rs_c,rs_y;
-
- if(! rs_portopen) /* is a port open? */
- return -1;
-
- if(rs_getcnt) /* was number of characters specified? */
- rs_y = rs_getcnt;
- else
- rs_y = rs_ss.ibuf_siz;
-
- while(rs_x < rs_y){
- if((rs_c = rs_getbyt()) < 0)
- break;
- else
- *(rs_getbuf + rs_x++) = (char)rs_c;
- if(! rs_getcnt){ /* if no length specified, end when nul is encountered */
- if(! rs_c)
- break;
- }
- }
-
- if(rs_getcnt) /* nul terminate if need be */
- *(rs_getbuf + rs_x) = '\0';
- return rs_x;
-
- }
-
- /* rs_inrcvd: Return number of received bytes waiting to be read from input
- buffer. */
- unsigned rs_inrcvd(void)
- {
-
- extern volatile struct rs_dynamics rs_ds;
- extern struct rs_statics rs_ss;
-
- if(rs_ds.rcv_cnt > rs_ss.ibuf_siz + 1){
- rs_ds.rcv_cnt = rs_ss.ibuf_siz + 2;
- return(rs_ss.ibuf_siz + 1);
- }
- else
- return rs_ds.rcv_cnt;
-
- }
-
- /* rs_error: Return last error detected as follows:
- bit 0: 1 = Buffer overrun
- bit 1: 1 = Receive data overrun
- bit 2: 1 = Parity error
- bit 3: 1 = Framing error
- bit 4: 1 = Break detected
- bit 7: 1 = Error in receive FIFO */
- int rs_error(void)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
- int rs_errtmp;
-
- rs_errtmp = (int)(rs_ds.err_cod & 0x9E);
- if(rs_ds.rcv_cnt > (rs_ss.ibuf_siz + 1)){ /* receive buffer overflow ? */
- rs_errtmp |= 0x01; /* set flag */
- rs_ds.rcv_cnt = rs_ss.ibuf_siz + 1;
- }
- rs_ds.err_cod = '\0';
- return rs_errtmp;
-
- }
-
- /* rs_modctrl: If rs_cmd = 0, return value of modem status register as of
- most recent change. If rs_cmd = 1, switch line determined by parameter1
- on or off depending on whether parameter2 is 1 or 0. If rs_cmd = 2,
- return contents of modem control register */
- int rs_modctrl(int rs_cmd,...)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
- extern int rs_portopen;
- unsigned char rs_cntrl;
- int rs_tmp = 0;
- va_list rs_ap;
-
- va_start(rs_ap,rs_cmd);
-
- if(rs_portopen){
- if(rs_cmd == 2)
- rs_tmp = inportb(rs_ss.mcr);
- else if(rs_cmd == 1){ /*manipulate control line (modem control reg.) */
- rs_cntrl = (unsigned char)(va_arg(rs_ap,int));
- if(va_arg(rs_ap,int))
- rs_cntrl |= inportb(rs_ss.mcr);
- else{
- rs_cntrl ^= '\xFF';
- rs_cntrl &= inportb(rs_ss.mcr);
- }
- outportb(rs_ss.mcr,rs_cntrl);
- }
- else{ /* get modem status register */
- rs_tmp = (int)rs_ds.msr_cod;
- rs_ds.msr_cod &= '\xF0';
- }
- }
- else /* no port open */
- rs_tmp = -1;
-
- va_end(rs_ap);
-
- return rs_tmp;
-
- }
-
- /* send break */
- int rs_break(void)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
- extern int rs_portopen;
- unsigned char rs_tmp;
- unsigned rs_time;
-
- if(! rs_portopen) /* is a port open? */
- return -1;
-
- rs_tmp = (char)inportb(rs_ss.lcr);
-
- while(rs_ds.out_tail != rs_ds.out_head)
- if(rs_ds.ier_msk == '\x0D')
- break;
-
- while(!((inportb(rs_ss.lsr)) & '\x20'))
- ;
-
- rs_tmp = inportb(rs_ss.lcr);
- rs_time = rs_timer(1);
- outportb(rs_ss.lcr,rs_tmp | '\x40');
- while(rs_timer(1) - rs_time < 4)
- ;
- outportb(rs_ss.lcr,rs_tmp);
-
- return 0;
-
- }
-
- /* clear input buffer */
- void rs_clrin(void)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
-
- if(! rs_portopen) /* is a port open? */
- return;
-
- disable();
- rs_ds.in_tail = rs_ds.in_head;
- rs_ds.rcv_cnt = 0;
- if(rs_ss.xmitfifo == 16) /* if FIFOs enabled */
- outportb(rs_ss.fcr,'\x43'); /* clear RCVR FIFO */
- enable();
-
- }
-
- /* clear output buffer */
- void rs_clrout(void)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
-
- if(! rs_portopen) /* is a port open? */
- return;
-
- disable();
- rs_ds.out_tail = rs_ds.out_head;
- if(rs_ss.xmitfifo == 16) /* if FIFOs enabled */
- outportb(rs_ss.fcr,'\x45'); /* clear XMIT FIFO */
- enable();
-
- }
-
- /* use BIOS keyboard buffer head and tail pointers to determine if a key
- has been pressed */
- int rs_keyhit(void)
- {
-
- volatile int far* rs_keytail;
- volatile int far* rs_keyhead;
-
- rs_keyhead = (int far*)MK_FP(0x40,0x1A);
- rs_keytail = rs_keyhead + 1;
-
- if(*rs_keytail == *rs_keyhead)
- return 0;
- else
- return 1;
-
- }
-
- /* use BIOS data area tick count to as 10/182 sec. resolution timer. If
- rs_cmd is 0, clear counter and return count up to that point. Id
- rs_cmd is non-zero, return tick count from the point which timer is
- last cleared. */
- unsigned rs_timer(int rs_cmd)
- {
-
- volatile unsigned long far* rs_biosticks;
- static long rs_startticks;
- unsigned rs_tmp;
-
- rs_biosticks = (unsigned long far*)MK_FP(0x40,0x6C);
-
- if(rs_cmd){
- if(*rs_biosticks >= rs_startticks)
- return((unsigned)(*rs_biosticks - rs_startticks));
- else
- return((unsigned)(*rs_biosticks + 1573040UL - rs_startticks));
- }
- else{
- if(*rs_biosticks >= rs_startticks)
- rs_tmp = (unsigned)(*rs_biosticks - rs_startticks);
- else
- rs_tmp = (unsigned)(*rs_biosticks + 1573040UL - rs_startticks);
- rs_startticks = *rs_biosticks;
- }
-
- return rs_tmp;
-
- }
-
- /* rs_setflow: rs_cmd = 0: Turn flow control off
- rs_cmd = 1: Set flow control to hardware - Parameter1
- is hardware line to monitor.
- rs_cmd = 2: Set flow control to XON/XOFF - Parameter1
- is character to use for XON, Parameter2
- is character to use for XOFF.
- rs_cmd = 3: Return status of flow control - 0 = output
- normal, 1 = output halted
- rs_cmd = 4: Insert control character in output stream.
- Parameter1 is control character.
- rs_cmd = 5: Manipulate hardware line. Parameter1 is bit
- pattern corresponding to line to change.
- If parameter2 is 0, line is turned off,
- if 1, line is turned on*/
- int rs_setflow(int rs_cmd,...)
- {
-
- extern struct rs_statics rs_ss;
- extern volatile struct rs_dynamics rs_ds;
- extern int rs_portopen;
- int rs_ret = 0;
- unsigned char rs_cntrl;
- va_list rs_ap;
-
- va_start(rs_ap, rs_cmd);
-
- if(rs_portopen){
- switch(rs_cmd){
- case 0: /* turn flow control off */
- rs_ss.flow = rs_cmd;
- break;
- case 1: /* set flow control to hardware */
- rs_ss.flow = rs_cmd;
- rs_ss.hdw_flw = ((char)va_arg(rs_ap,int)) << 4;
- if((inportb(rs_ss.msr)) & rs_ss.hdw_flw)
- rs_ds.ier_msk = '\x0F';
- else
- rs_ds.ier_msk = '\x0D';
- break;
- case 2: /* set flow control to XON/XOFF */
- rs_ss.flow = rs_cmd;
- rs_ss.xon = (char)(va_arg(rs_ap,int));
- rs_ss.xoff = (char)(va_arg(rs_ap,int));
- break;
- case 3: /* return status of flow control */
- rs_ret = (rs_ds.ier_msk == '\x0D');
- break;
- case 4: /* insert control character in output stream */
- rs_cntrl = (char)(va_arg(rs_ap,int));
- #ifndef RS_POLLED_XMIT
- outportb(rs_ss.ier,'\x0D');
- #endif
- while(!(inportb(rs_ss.lsr) & '\x20'))
- ;
- outportb(rs_ss.thr,rs_cntrl);
- #ifndef RS_POLLED_XMIT
- outportb(rs_ss.ier,rs_ds.ier_msk);
- #endif
- break;
- }
- }
- else /* no port open */
- rs_ret = -1;
-
- va_end(rs_ap);
-
- return rs_ret;
-
- }